/** @file

  Copyright (C) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "LocalAmlLib.h"

/**
  ResourceTemplate (Resource To Buffer Conversion Macro)

  Syntax:
  ResourceTemplate () {ResourceMacroList} => Buffer

  @param[in]      Phase     - Either AmlStart or AmlClose
  @param[in,out]  ListHead  - Linked list has completed ResourceTemplate Object
                              after AmlClose.

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlResourceTemplate (
  IN      AML_FUNCTION_PHASE  Phase,
  IN OUT  LIST_ENTRY          *ListHead
  )
{
  EFI_STATUS                   Status;
  AML_OBJECT_INSTANCE          *Object;
  AML_OBJECT_INSTANCE          *ChildObject;
  UINTN                        ChildCount;
  EFI_ACPI_END_TAG_DESCRIPTOR  *EndTag;

  if ((Phase >= AmlInvalid) || (ListHead == NULL)) {
    return EFI_INVALID_PARAMETER;
  }

  Status      = EFI_DEVICE_ERROR;
  Object      = NULL;
  ChildObject = NULL;

  switch (Phase) {
    case AmlStart:
      Status = AmlBuffer (AmlStart, 0, ListHead);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __FUNCTION__, "ResourceTemplate"));
        goto Done;
      }

      // Start EndTag object to be completed in Close
      // ACPI 6.3: 6.4.2.9 End Tag: ...The End Tag is automatically generated by
      // the ASL compiler at the end of the ResourceTemplate statement.
      Status = InternalAppendNewAmlObject (&Object, "END_TAG", ListHead);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __FUNCTION__, "END_TAG"));
        goto Done;
      }

      // ResourceMacroList is too complicated and must be added outside
      break;
    case AmlClose:
      // ResourceMacroList should be closed already

      // Locate and complete End Tag
      Status = InternalAmlLocateObjectByIdentifier (&Object, "END_TAG", ListHead);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __FUNCTION__, "END_TAG"));
        goto Done;
      }

      // Release Object->Data Identifier
      InternalFreeAmlObjectData (Object);

      // Collect child data and delete children
      Status = InternalAmlCollapseAndReleaseChildren (
                 &ChildObject,
                 &ChildCount,
                 &Object->Link,
                 ListHead
                 );
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: collecting Child data\n", __FUNCTION__));
        goto Done;
      }

      Object->DataSize = ChildObject->DataSize + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);
      Object->Data     = AllocateZeroPool (Object->DataSize);
      if (Object->Data == NULL) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: EndTag Alloc Failed\n", __FUNCTION__));
        Status = EFI_OUT_OF_RESOURCES;
        goto Done;
      }

      // ChildObject Data goes before End Tag
      if ((ChildObject->Data != NULL) && (ChildObject->DataSize > 0)) {
        CopyMem (Object->Data, ChildObject->Data, ChildObject->DataSize);
      }

      EndTag       = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Object->Data[ChildObject->DataSize];
      EndTag->Desc = ACPI_END_TAG_DESCRIPTOR;
      // Spec says the byte is a checksum, but I have never seen a value other
      // than zero in the field compiled from ASL.
      // EndTag->Checksum already = 0;

      InternalFreeAmlObject (&ChildObject, ListHead);
      Object->Completed = TRUE;

      Status = AmlBuffer (AmlClose, 0, ListHead);
      if (EFI_ERROR (Status)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: Close %a object\n", __FUNCTION__, "ResourceTemplate"));
        goto Done;
      }

      Status = EFI_SUCCESS;
      break;

    default:
      Status = EFI_DEVICE_ERROR;
      break;
  }

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  InternalAmlAddressSpaceCheck

  Checks Address space parameters for Word, DWord, or QWord size Address space
  Descriptor.  Size will be constrained by the Resource Descriptor input
  parameters being of the correct size.

  @param[in]      IsMinFixed
  @param[in]      IsMaxFixed
  @param[in]      AddressGranularity
  @param[in]      AddressMinimum
  @param[in]      AddressMaximum
  @param[in]      RangeLength

**/
EFI_STATUS
EFIAPI
InternalAmlAddressSpaceCheck (
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT64  AddressGranularity,
  IN      UINT64  AddressMinimum,
  IN      UINT64  AddressMaximum,
  IN      UINT64  RangeLength
  )
{
  // Max must be greater than Min
  if (AddressMaximum < AddressMinimum) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: AddressMinimum greater than AddressMaximum\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  // Address Granularity must be (2^n)-1
  if (((AddressGranularity + 1) & AddressGranularity) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: AddressGranularity must be (a power of 2)-1\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if (RangeLength == 0) {
    // LEN _MIF _MAF Definition
    //   0    0    0
    //   0    0    1
    //   0    1    0
    //          Variable size, variable location resource descriptor for _PRS.
    //          If _MIF is set, _MIN must be a multiple of (_GRA+1). If _MAF
    //            is set, _MAX must be (a multiple of (_GRA+1))-1.
    //          OS can pick the resource range that satisfies following conditions:
    //          If _MIF is not set, start address is a multiple of (_GRA+1)
    //            and greater or equal to _MIN. Otherwise, start address is _MIN.
    //          If _MAF is not set, end address is (a multiple of (_GRA+1))-1
    //            and less or equal to _MAX. Otherwise, end address is _MAX.
    //   0    1    1  (Invalid combination)
    if ((IsMinFixed == EFI_ACPI_GENERAL_FLAG_MIN_IS_FIXED) &&
        (IsMaxFixed == EFI_ACPI_GENERAL_FLAG_MAX_IS_FIXED))
    {
      //   0    1    1  (Invalid combination)
      DEBUG ((DEBUG_ERROR, "%a: ERROR: IsMinFixed and IsMaxFixed cannot both be set\n", __FUNCTION__));
      DEBUG ((DEBUG_ERROR, "%a:        When RangeLength=0x%lX\n", __FUNCTION__, RangeLength));
      return EFI_INVALID_PARAMETER;
    } else if (IsMaxFixed == EFI_ACPI_GENERAL_FLAG_MAX_IS_FIXED) {
      //   0    0    1
      if ((AddressMaximum & AddressGranularity) != AddressGranularity) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: (AddressMaximum=0x%lX + 1) is not a multiple of\n", __FUNCTION__, AddressMaximum));
        DEBUG ((DEBUG_ERROR, "%a:        (AddressGranularity=0x%lX + 1)\n", __FUNCTION__, AddressGranularity));
        DEBUG ((DEBUG_ERROR, "%a:        When IsMaxFixed = 1\n", __FUNCTION__));
        return EFI_INVALID_PARAMETER;
      }

      if (AddressMaximum == 0) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: AddressMaximum can not be 0\n", __FUNCTION__));
        DEBUG ((DEBUG_ERROR, "%a:        When IsMaxFixed = 1\n", __FUNCTION__));
        return EFI_INVALID_PARAMETER;
      }
    } else if (IsMinFixed == EFI_ACPI_GENERAL_FLAG_MIN_IS_FIXED) {
      //   0    1    0
      if ((AddressMinimum & AddressGranularity) != 0) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: AddressMinimum=0x%lX is not a multiple of\n", __FUNCTION__, AddressMinimum));
        DEBUG ((DEBUG_ERROR, "%a:        (AddressGranularity=0x%lX + 1)\n", __FUNCTION__, AddressGranularity));
        DEBUG ((DEBUG_ERROR, "%a:        When IsMinFixed = 1\n", __FUNCTION__));
        return EFI_INVALID_PARAMETER;
      }
    } else if ((IsMinFixed == EFI_ACPI_GENERAL_FLAG_MIN_IS_NOT_FIXED) &&
               (IsMaxFixed == EFI_ACPI_GENERAL_FLAG_MAX_IS_NOT_FIXED) &&
               (AddressMinimum == 0) &&
               (AddressMaximum == 0) &&
               (AddressGranularity == 0))
    {
      DEBUG ((DEBUG_ERROR, "%a: ERROR: Maximum, Minimum, Granularity all 0\n", __FUNCTION__));
      return EFI_INVALID_PARAMETER;
    }
  } else {
    // LEN _MIF _MAF Definition
    //  >0    0    0  Fixed size, variable location resource descriptor for _PRS.
    //                _LEN must be a multiple of (_GRA+1).
    //                OS can pick the resource range that satisfies following conditions:
    //                Start address is a multiple of (_GRA+1) and greater or equal to _MIN.
    //                End address is (start address+_LEN-1) and less or equal to _MAX.
    //  >0    0    1  (Invalid combination)
    //  >0    1    0  (Invalid combination)
    //  >0    1    1  Fixed size, fixed location resource descriptor.
    //                _GRA must be 0 and _LEN must be (_MAX - _MIN +1).
    if ((IsMinFixed == EFI_ACPI_GENERAL_FLAG_MIN_IS_NOT_FIXED) &&
        (IsMaxFixed == EFI_ACPI_GENERAL_FLAG_MAX_IS_NOT_FIXED))
    {
      //  >0    0    0
      if ((RangeLength & AddressGranularity) != 0) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: RangeLength=0x%lX is not a multiple of\n", __FUNCTION__, RangeLength));
        DEBUG ((DEBUG_ERROR, "%a:        (AddressGranularity=0x%lX + 1)\n", __FUNCTION__, AddressGranularity));
        DEBUG ((DEBUG_ERROR, "%a:        When IsMinFixed = 0, IsMaxFixed = 0\n", __FUNCTION__));
        return EFI_INVALID_PARAMETER;
      } else if (RangeLength > (AddressMaximum - AddressMinimum + 1)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: RangeLength=0x%lX > (AddrRangeMax=0x%lX - AddrRangeMin=0x%lX + 1)\n", __FUNCTION__, RangeLength, AddressMaximum, AddressMinimum));
        DEBUG ((DEBUG_ERROR, "%a:        IsMinFixed = 0, IsMaxFixed = 0\n", __FUNCTION__, RangeLength));
        return EFI_INVALID_PARAMETER;
      }
    } else if ((IsMinFixed == EFI_ACPI_GENERAL_FLAG_MIN_IS_FIXED) &&
               (IsMaxFixed == EFI_ACPI_GENERAL_FLAG_MAX_IS_FIXED))
    {
      //  >0    1    1
      if (AddressGranularity != 0) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: AddressGranularity=0x%lX != 0\n", __FUNCTION__, AddressGranularity));
        DEBUG ((DEBUG_ERROR, "%a:        When RangeLength=0x%lX > 0, IsMinFixed = 1, and IsMaxFixed = 1\n", __FUNCTION__, RangeLength));
        return EFI_INVALID_PARAMETER;
      } else if (RangeLength != (AddressMaximum - AddressMinimum + 1)) {
        DEBUG ((DEBUG_ERROR, "%a: ERROR: RangeLength=0x%lX != (AddrRangeMax=0x%lX - AddrRangeMin=0x%lX + 1)\n", __FUNCTION__, RangeLength, AddressMaximum, AddressMinimum));
        DEBUG ((DEBUG_ERROR, "%a:        IsMinFixed = 1, IsMaxFixed = 1\n", __FUNCTION__, RangeLength));
        return EFI_INVALID_PARAMETER;
      }
    } else {
      //  >0    0    1  (Invalid combination)
      //  >0    1    0  (Invalid combination)
      DEBUG ((DEBUG_ERROR, "%a: ERROR: When RangeLength=0x%lX > 0,\n", __FUNCTION__, RangeLength));
      DEBUG ((DEBUG_ERROR, "%a:        IsMinFixed and IsMaxFixed must both be either 1 or 0\n", __FUNCTION__));
      return EFI_INVALID_PARAMETER;
    }
  }

  return EFI_SUCCESS;
}

/*
  Internal function to create DWord Address Space Descriptors

  This function only requires a single call and therefore no Phases
  Generates:
  6.4.3.5.2 DWord Address Space Descriptor
  Type 1, Large Item Value 0x7
  The DWORD address space descriptor is used to report resource usage in a
  32-bit address space (like memory and I/O).

  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed DWordSpace buffer

  @retval         EFI_SUCCESS
  @retval         Error status
*/
EFI_STATUS
EFIAPI
InternalAmlOPDWordAddressSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT32  AddressGranularity,
  IN      UINT32  AddressMinimum,
  IN      UINT32  AddressMaximum,
  IN      UINT32  AddressTranslation,
  IN      UINT32  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS                               Status;
  AML_OBJECT_INSTANCE                      *Object;
  EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;

  // Vaidate General Flags Input
  if ((ResourceUsage & ~EFI_ACPI_GENERAL_FLAG_MASK_USAGE) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Dword Invalid ResourceUsage Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((Decode & ~EFI_ACPI_GENERAL_FLAG_MASK_DEC) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Dword Invalid Decode Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMinFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MIF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Dword Invalid IsMinFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMaxFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MAF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Dword Invalid IsMaxFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlAddressSpaceCheck (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: DWord Address Space Check FAILED\n", __FUNCTION__));
    return Status;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __FUNCTION__, "DWORD_ADDRESS"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "DWORD_ADDRESS"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor                     = (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Header.Byte = ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR;
  Descriptor->Header.Length      = sizeof (EFI_ACPI_DWORD_ADDRESS_SPACE_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);
  Descriptor->ResType               = ResourceType;
  Descriptor->GenFlag               = IsMinFixed | IsMaxFixed | Decode;
  Descriptor->SpecificFlag          = TypeSpecificFlags;
  Descriptor->AddrSpaceGranularity  = AddressGranularity;
  Descriptor->AddrRangeMin          = AddressMinimum;
  Descriptor->AddrRangeMax          = AddressMaximum;
  Descriptor->AddrTranslationOffset = AddressTranslation;
  Descriptor->AddrLen               = RangeLength;
  Object->Completed                 = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.32 DMA (DMA Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  DMA (DmaType, IsBusMaster, DmaTransferSize, DescriptorName) {DmaChannelList} => Buffer (BitMask)

  Generates: 6.4.2.2 DMA Descriptor

  @param[in]      DmaType         - DMA channel speed supported
  @param[in]      IsBusMaster     - Logical device bus master status
  @param[in]      DmaTransferSize - DMA transfer type preference (8-bit, 16-bit, both)
  @param[in]      DmaChannelList  - DMA channel mask bits [7:0] (channels 0 - 7), _DMA
                                    Bit [0] is channel 0, etc.
  //              DescriptorName  - Optional - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed DWordIO buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPDma (
  IN      EFI_ACPI_DMA_SPEED_TYPE_KEYWORDS     DmaType,
  IN      EFI_ACPI_DMA_BUS_MASTER_KEYWORDS     IsBusMaster,
  IN      EFI_ACPI_DMA_TRANSFER_TYPE_KEYWORDS  DmaTransferSize,
  IN      UINT8                                DmaChannelList,
  //                                          DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY                           *ListHead
  )
{
  EFI_STATUS               Status;
  AML_OBJECT_INSTANCE      *Object;
  EFI_ACPI_DMA_DESCRIPTOR  *Descriptor;

  if ((DmaType & (UINT8) ~EFI_ACPI_DMA_SPEED_TYPE_MASK) != 0) {
    // Invalid DmaType value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: DmaType '%x' is not valid.\n", __FUNCTION__, DmaType));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsBusMaster & ~EFI_ACPI_DMA_BUS_MASTER_MASK) != 0) {
    // Invalid IsBusMaster value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: IsBusMaster '%x' is not valid.\n", __FUNCTION__, DmaType));
    return EFI_INVALID_PARAMETER;
  }

  if (((DmaTransferSize & ~EFI_ACPI_DMA_TRANSFER_TYPE_MASK) != 0) ||
      (DmaTransferSize == 0x3))
  {
    // Invalid DmaTransferSize value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: DmaTransferSize '%x' is not valid.\n", __FUNCTION__, DmaType));
    return EFI_INVALID_PARAMETER;
  }

  if (ListHead == NULL) {
    // Invalid
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid parameter, ListHead cannot == NULL.\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a cannot create %a object.", __FUNCTION__, "DMA_RESOURCE"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_DMA_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "DMA_RESOURCE"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor              = (EFI_ACPI_DMA_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Byte = ACPI_DMA_DESCRIPTOR;
  Descriptor->ChannelMask = DmaChannelList;
  //
  // Descriptor->Information bit mask:
  //    Bit [7]    Reserved (must be 0)
  //    Bits [6:5] DMA channel speed supported, _TYP
  //      00 Indicates compatibility mode
  //      01 Indicates Type A DMA as described in the EISA
  //      10 Indicates Type B DMA
  //      11 Indicates Type F
  //    Bits [4:3] Ignored
  //    Bit [2] Logical device bus master status, _BM
  //      0 Logical device is not a bus master
  //      1 Logical device is a bus master
  //    Bits [1:0] DMA transfer type preference, _SIZ
  //      00 8-bit only
  //      01 8- and 16-bit
  //      10 16-bit only
  Descriptor->Information =  (UINT8)(DmaType +
                                     IsBusMaster +
                                     DmaTransferSize);
  Object->Completed = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.35 DWordSpace (DWord Space Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  DWordSpace (ResourceType, ResourceUsage, Decode, IsMinFixed, IsMaxFixed,
              TypeSpecificFlags, AddressGranularity, AddressMinimum,
              AddressMaximum, AddressTranslation, RangeLength,
              ResourceSourceIndex, ResourceSource, DescriptorName)

  Generates:
  6.4.3.5.2 DWord Address Space Descriptor
  Type 1, Large Item Value 0x7

  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed DWordSpace buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPDWordSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT32  AddressGranularity,
  IN      UINT32  AddressMinimum,
  IN      UINT32  AddressMaximum,
  IN      UINT32  AddressTranslation,
  IN      UINT32  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  // UINT8 ResourceType cannot be > 0xFF, so no need to check top end.
  if (ResourceType < EFI_ACPI_SPACE_RESOURCE_TYPE_MIN) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid ResourceType\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPDWordAddressSpace (
             ResourceType,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             TypeSpecificFlags,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.33 DWordIO (DWord IO Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  DWordIO (ResourceUsage, IsMinFixed, IsMaxFixed, Decode, ISARanges,
           AddressGranularity, AddressMinimum, AddressMaximum,
           AddressTranslation, RangeLength, ResourceSourceIndex,
           ResourceSource, DescriptorName, TranslationType,
           TranslationDensity)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Decode,
  @param[in]      ISARanges,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
                  TranslationType - NOT IMPLEMENTED
                  TranslationDensity - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed DWordIO buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPDWordIO (
  IN      UINT8   ResourceUsage,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Decode,
  IN      UINT8   ISARanges,
  IN      UINT32  AddressGranularity,
  IN      UINT32  AddressMinimum,
  IN      UINT32  AddressMaximum,
  IN      UINT32  AddressTranslation,
  IN      UINT32  RangeLength,
  //                    ResourceSourceIndex - NOT IMPLEMENTED
  //                    ResourceSource - NOT IMPLEMENTED
  //                    DescriptorName - NOT IMPLEMENTED
  //                    TranslationType - NOT IMPLEMENTED
  //                    TranslationDensity - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  if (ISARanges == 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges = 0 = Reserved\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  } else if (ISARanges > 3) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges > 3 are Invalid\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPDWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_IO,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             (ISARanges),
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.34 DWordMemory (DWord Memory Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  DWordMemory (ResourceUsage, Decode, IsMinFixed, IsMaxFixed, Cacheable,
               ReadAndWrite, AddressGranularity, AddressMinimum, AddressMaximum,
               AddressTranslation, RangeLength, ResourceSourceIndex,
               ResourceSource, DescriptorName, MemoryRangeType, TranslationType)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Cacheable,
  @param[in]      ReadAndWrite,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
                  MemoryRangeType - NOT IMPLEMENTED
                  TranslationType - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed DWordMemory buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPDWordMemory (
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Cacheable,
  IN      UINT8   ReadAndWrite,
  IN      UINT32  AddressGranularity,
  IN      UINT32  AddressMinimum,
  IN      UINT32  AddressMaximum,
  IN      UINT32  AddressTranslation,
  IN      UINT32  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  //                  MemoryRangeType - NOT IMPLEMENTED
  //                  TranslationType - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  // Validate Type Specific Parameters
  if ((Cacheable & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_MEM) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid Cacheable Parameter 0x%X\n", __FUNCTION__, (Cacheable & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_MEM)));
    return EFI_INVALID_PARAMETER;
  }

  if ((ReadAndWrite & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_RW) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid ReadAndWrite Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPDWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_MEM,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             (Cacheable | ReadAndWrite),
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/*
  Internal function to create QWord Address Space Descriptors

  This function only requires a single call and therefore no Phases
  Generates:
  6.4.3.5.1 QWord Address Space Descriptor
  Type 1, Large Item Value 0xA
  The QWORD address space descriptor is used to report resource usage in a
  64-bit address space (like memory and I/O).

  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed QWordSpace buffer

  @retval         EFI_SUCCESS
  @retval         Error status
*/
EFI_STATUS
EFIAPI
InternalAmlOPQWordAddressSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT64  AddressGranularity,
  IN      UINT64  AddressMinimum,
  IN      UINT64  AddressMaximum,
  IN      UINT64  AddressTranslation,
  IN      UINT64  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS                               Status;
  AML_OBJECT_INSTANCE                      *Object;
  EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;

  // Vaidate General Flags Input
  if ((ResourceUsage & ~EFI_ACPI_GENERAL_FLAG_MASK_USAGE) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Qword Invalid ResourceUsage Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((Decode & ~EFI_ACPI_GENERAL_FLAG_MASK_DEC) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Qword Invalid Decode Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMinFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MIF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Qword Invalid IsMinFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMaxFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MAF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Qword Invalid IsMaxFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlAddressSpaceCheck (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: QWord Address Space Check FAILED\n", __FUNCTION__));
    return Status;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __FUNCTION__, "QWORD_ADDRESS"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "QWORD_ADDRESS"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor                     = (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Header.Byte = ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR;
  Descriptor->Header.Length      = sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);
  Descriptor->ResType               = ResourceType;
  Descriptor->GenFlag               = IsMinFixed | IsMaxFixed | Decode;
  Descriptor->SpecificFlag          = TypeSpecificFlags;
  Descriptor->AddrSpaceGranularity  = AddressGranularity;
  Descriptor->AddrRangeMin          = AddressMinimum;
  Descriptor->AddrRangeMax          = AddressMaximum;
  Descriptor->AddrTranslationOffset = AddressTranslation;
  Descriptor->AddrLen               = RangeLength;
  Object->Completed                 = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.65 IRQ (Interrupt Resource Descriptor Macro)

  Syntax:
    IRQ (EdgeLevel, ActiveLevel, Shared, DescriptorName) {InterruptList} => Buffer

  Arguments:
    EdgeLevel:
      Describes whether the interrupt is edge triggered (Edge) or level triggered
      (Level). The field DescriptorName. _HE is automatically created to refer to
      this portion of the resource descriptor, where '1' is Edge and ActiveHigh
      and '0' is Level and ActiveLow.

    ActiveLevel:
      Describes whether the interrupt is active-high (ActiveHigh) or active-low
      (ActiveLow). The field DescriptorName. _LL is automatically created to refer
      to this portion of the resource descriptor, where '1' is Edge and ActiveHigh
      and '0' is Level and ActiveLow.

    Shared:
      Describes whether the interrupt can be shared with other devices (Shared) or
      not (Exclusive), and whether it is capable of waking the system from a
      low-power idle or system sleep state (SharedAndWake or ExclusiveAndWake).
      The field DescriptorName. _SHR is automatically created to refer to this portion
      of the resource descriptor, where '1' is Shared and '0' is Exclusive. If nothing
      is specified, then Exclusive is assumed.

    InterruptList:
      IRQ mask bits [15:0]
      Bit[0] represents IRQ0, bit[1] is IRQ1, etc.

    DescriptorName:
      Is an optional argument that specifies a name for an integer constant that
      will be created in the current scope that contains the offset of this resource
      descriptor within the current resource template buffer. The predefined
      descriptor field names may be appended to this name to access individual
      fields within the descriptor via the Buffer Field operators.

    Description:
      The IRQ macro evaluates to a buffer that contains an IRQ resource descriptor.
      The format of the IRQ descriptor can be found in "IRQ Descriptor". The macro
      produces the three-byte form of the descriptor. The macro is designed to be
      used inside of a ResourceTemplate.

  Generates: 6.4.2.1 IRQ Descriptor

  @param[in]      EdgeLevel       - trigger level supported
  @param[in]      ActiveLevel     - interrupt polarity
  @param[in]      Shared          - interrupt exclusivity
  @param[in]      InterruptList   - IRQ mask bits[7:0], _INT
                                      Bit [0] represents IRQ0,
                                      bit[1] is IRQ1, and so on.
                                    IRQ mask bits[15:8], _INT
                                      Bit [0] represents IRQ8,
                                      bit[1] is IRQ9, and so on.
  //              DescriptorName  - Optional - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed IRQ buffer

  @retval         EFI_SUCCESS
  @retval         Error status

**/
EFI_STATUS
EFIAPI
AmlOPIRQ (
  IN      EFI_ACPI_IRQ_INTERRUPT_MODE_KEYWORDS      EdgeLevel,
  IN      EFI_ACPI_IRQ_INTERRUPT_POLARITY_KEYWORDS  ActiveLevel,
  IN      EFI_ACPI_IRQ_INTERRUPT_SHARING_KEYWORDS   Shared,
  IN      UINT16                                    InterruptList,
  //                                                DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY                                *ListHead
  )
{
  EFI_STATUS               Status;
  AML_OBJECT_INSTANCE      *Object;
  EFI_ACPI_IRQ_DESCRIPTOR  *Descriptor;

  if ((EdgeLevel & (UINT8) ~EFI_ACPI_IRQ_MODE_MASK) != 0) {
    // Invalid Decode value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: EdgeLevel '%x' is not valid.\n", __FUNCTION__, EdgeLevel));
    return EFI_INVALID_PARAMETER;
  }

  if ((ActiveLevel & (UINT8) ~EFI_ACPI_IRQ_POLARITY_MASK) != 0) {
    // Invalid Decode value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ActiveLevel '%x' is not valid.\n", __FUNCTION__, ActiveLevel));
    return EFI_INVALID_PARAMETER;
  }

  if ((Shared & (UINT8) ~(EFI_ACPI_IRQ_WAKE_CAPABLE_MASK | EFI_ACPI_IRQ_SHARABLE_MASK)) != 0) {
    // Invalid Decode value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Shared '%x' is not valid.\n", __FUNCTION__, Shared));
    return EFI_INVALID_PARAMETER;
  }

  if (ListHead == NULL) {
    // Invalid
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid parameter, ListHead cannot == NULL.\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Cannot create %a object.", __FUNCTION__, "IRQ_RESOURCE"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_IRQ_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Alloc for %a failed\n", __FUNCTION__, "IRQ_RESOURCE"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor              = (EFI_ACPI_IRQ_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Byte = ACPI_IRQ_DESCRIPTOR;
  Descriptor->Mask        = InterruptList;
  //
  // Ref 6.4.2.1 IRQ Descriptor - IRQ Information
  // Descriptor->Information bit mask:
  //  IRQ Information. Each bit, when set, indicates this device is capable of
  //  driving a certain type of interrupt.  (Optional-if not included then assume
  //  edge sensitive, high true interrupts.) These bits can be used both for
  //  reporting and setting IRQ resources.
  //  Note: This descriptor is meant for describing interrupts that are connected
  //    to PIC-compatible interrupt controllers, which can only be programmed
  //    for Active-High-Edge-Triggered or Active-Low-LevelTriggered interrupts.
  //    Any other combination is invalid. The Extended Interrupt Descriptor can
  //    be used to describe other combinations.
  //
  //  Bit [7:6] Reserved (must be 0)
  //  Bit [5] Wake Capability, _WKC
  //   0x0 = Not Wake Capable: This interrupt is not capable of waking the system.
  //   0x1 = Wake Capable: This interrupt is capable of waking the system from a
  //   low-power idle state or a system sleep state.
  //  Bit [4] Interrupt Sharing, _SHR
  //   0x0 = Exclusive: This interrupt is not shared with other devices.
  //   0x1 = Shared: This interrupt is shared with other devices.
  //  Bit [3] Interrupt Polarity, _LL
  //   0 Active-High - This interrupt is sampled when the signal is high, or true
  //   1 Active-Low - This interrupt is sampled when the signal is low, or false.
  //  Bit [2:1] Ignored
  //  Bit [0] Interrupt Mode, _HE
  //   0 Level-Triggered - Interrupt is triggered in response to signal in a low state.
  //   1 Edge-Triggered - Interrupt is triggered in response to a change in signal state from
  //   low to high.
  //
  Descriptor->Information = (UINT8)((EFI_ACPI_IRQ_WAKE_CAPABLE_MASK |
                                     EFI_ACPI_IRQ_SHARABLE_MASK |
                                     EFI_ACPI_IRQ_POLARITY_MASK |
                                     EFI_ACPI_IRQ_MODE_MASK) &
                                    (Shared |
                                     ActiveLevel |
                                     EdgeLevel));
  Object->Completed = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.64 IO (IO Resource Descriptor Macro)

  Syntax:
    IO (Decode, AddressMin, AddressMax, AddressAlignment, RangeLength, DescriptorName) => Buffer

  Arguments:
    Decode:
      Describes whether the I/O range uses 10-bit decode (Decode10) or 16-bit
      decode (Decode16).  The field DescriptorName. _DEC is automatically created
      to refer to this portion of the resource descriptor, where '1' is Decode16
      and '0' is Decode10.

    AddressMin:
      Evaluates to a 16-bit integer that specifies the minimum acceptable starting
      address for the I/O range. It must be an even multiple of AddressAlignment.
      The field DescriptorName._MIN is automatically created to refer to this
      portion of the resource descriptor.

    AddressMax:
      Evaluates to a 16-bit integer that specifies the maximum acceptable starting
      address for the I/O range. It must be an even multiple of AddressAlignment.
      The field DescriptorName._MAX is automatically created to refer to this
      portion of the resource descriptor.

    AddressAlignment:
      Evaluates to an 8-bit integer that specifies the alignment granularity
      for the I/O address assigned. The field DescriptorName. _ALN is automatically
      created to refer to this portion of the resource descriptor.

    RangeLength:
      Evaluates to an 8-bit integer that specifies the number of bytes in the
      I/O range. The field DescriptorName. _LEN is automatically created to refer
      to this portion of the resource descriptor.

    DescriptorName:
      An optional argument that specifies a name for an integer constant that
      will be created in the current scope that contains the offset of this
      resource descriptor within the current resource template buffer. The
      predefined descriptor field names may be appended to this name to access
      individual fields within the descriptor via the Buffer Field operators.

  Description:
    The IO macro evaluates to a buffer which contains an IO resource descriptor.
    The format of the IO descriptor can be found in the ACPI Specification section
    "I/O Port Descriptor".  The macro is designed to be used inside of a ResourceTemplate.

  Generates:
    6.4.2.5 I/O Port Descriptor
    Type 0, Small Item Name 0x8, Length = 7

  @param[in]      Decode,
  @param[in]      AddressMin,
  @param[in]      AddressMax,
  @param[in]      AddressAlignment,
  @param[in]      RangeLength,
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed IO buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPIO (
  IN      EFI_ACPI_IO_PORT_DESCRIPTOR_INFORMATION  Decode,
  IN      UINT16                                   AddressMin,
  IN      UINT16                                   AddressMax,
  IN      UINT8                                    AddressAlignment,
  IN      UINT8                                    RangeLength,
  //                                               DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY                               *ListHead
  )
{
  EFI_STATUS                   Status;
  AML_OBJECT_INSTANCE          *Object;
  EFI_ACPI_IO_PORT_DESCRIPTOR  *Descriptor;
  UINT64                       Remainder;

  if ((Decode & (UINT8) ~EFI_ACPI_IO_DECODE_MASK) != 0) {
    // Invalid Decode value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Decode '%x' is not valid.\n", __FUNCTION__, Decode));
    return EFI_INVALID_PARAMETER;
  }

  if (ListHead == NULL) {
    // Invalid
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid parameter, ListHead cannot == NULL.\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if (AddressAlignment != 0) {
    DivU64x64Remainder (AddressMin, AddressAlignment, &Remainder);
    if (Remainder != 0) {
      DEBUG ((DEBUG_ERROR, "%a: ERROR: (AddressMin=0x%X) is not a multiple of\n", __FUNCTION__, AddressMin));
      DEBUG ((DEBUG_ERROR, "%a:        (AddressAlignment)=0x%X\n", __FUNCTION__, AddressAlignment));
      return EFI_INVALID_PARAMETER;
    }

    DivU64x64Remainder (AddressMax, AddressAlignment, &Remainder);
    if (Remainder != 0) {
      DEBUG ((DEBUG_ERROR, "%a: ERROR: (AddressMax=0x%X) is not a multiple of\n", __FUNCTION__, AddressMax));
      DEBUG ((DEBUG_ERROR, "%a:        (AddressAlignment)=0x%X\n", __FUNCTION__, AddressAlignment));
      return EFI_INVALID_PARAMETER;
    }
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a cannot create %a object.", __FUNCTION__, "IO_RESOURCE"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_IO_PORT_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "IO_RESOURCE"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor = (EFI_ACPI_IO_PORT_DESCRIPTOR *)Object->Data;

  /*
   * According to ACPI spec for
   * ACPI_IO_PORT_DESCRIPTOR = 0x47 contains the informaion about
   *  Name, Type and Length, hence no need to calculate the length.
   *  Below is description from ACPI spec
   * Byte 0 I/O Port Descriptor Value = 0x47 (01000111B) - Type = 0, Small item name =
   *  0x8, Length = 7
   */
  Descriptor->Header.Byte = ACPI_IO_PORT_DESCRIPTOR;
  //
  // Descriptor->Information bit mask:
  //    Bit [7:1]  Reserved, must be 0
  //    Bit [0]    (_DEC)
  //      1 The logical device decodes 16-bit addresses
  //      0 The logical device decodes 10-bit addresses
  Descriptor->Information    = (UINT8)(EFI_ACPI_IO_DECODE_MASK & Decode);
  Descriptor->BaseAddressMin = AddressMin;
  Descriptor->BaseAddressMax = AddressMax;
  Descriptor->Alignment      = AddressAlignment;
  Descriptor->Length         = RangeLength;
  Object->Completed          = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/*
  19.6.114 Register (Generic Register Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  Register (AddressSpaceKeyword, RegisterBitWidth, RegisterBitOffset,
            RegisterAddress, AccessSize, DescriptorName)

  Generates:
  6.4.3.7 Generic Register Descriptor
  Type 1, Large Item Value 0x2
  The generic register descriptor describes the location of a fixed width
  register within any of the ACPI-defined address spaces. See Generic Register
  Descriptor for details.


  @param[in]      AddressSpaceKeyword,
  @param[in]      RegisterBitWidth,
  @param[in]      RegisterBitOffset,
  @param[in]      RegisterAddress,
  @param[in]      AccessSize,
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed QWordSpace buffer

  @retval         EFI_SUCCESS
  @retval         Error status
*/
EFI_STATUS
EFIAPI
AmlOPRegister (
  IN      GENERIC_ADDRESS_SPACE_ID  AddressSpaceKeyword,
  IN      UINT8                     RegisterBitWidth,
  IN      UINT8                     RegisterBitOffset,
  IN      UINT64                    RegisterAddress,
  IN      UINT8                     AccessSize,
  //                                DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY                *ListHead
  )
{
  EFI_STATUS                            Status;
  AML_OBJECT_INSTANCE                   *Object;
  EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR  *Descriptor;

  if ((AddressSpaceKeyword < EFI_ACPI_6_4_SYSTEM_MEMORY) ||
      (AddressSpaceKeyword > EFI_ACPI_6_4_FUNCTIONAL_FIXED_HARDWARE))
  {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid AddressSpaceKeyword=0x%02X\n", __FUNCTION__, AddressSpaceKeyword));
    return EFI_INVALID_PARAMETER;
  }

  if ((AddressSpaceKeyword > EFI_ACPI_6_4_PLATFORM_COMMUNICATION_CHANNEL) &&
      (AddressSpaceKeyword < EFI_ACPI_6_4_FUNCTIONAL_FIXED_HARDWARE))
  {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid AddressSpaceKeyword=0x%02X\n", __FUNCTION__, AddressSpaceKeyword));
    return EFI_INVALID_PARAMETER;
  }

  if (AccessSize > EFI_ACPI_6_4_QWORD) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid AccessSize=0x%02X\n", __FUNCTION__, AccessSize));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a cannot create %a object.", __FUNCTION__, "IO_RESOURCE"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "IO_RESOURCE"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor = (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR *)Object->Data;

  Descriptor->Header.Header.Byte = ACPI_GENERIC_REGISTER_DESCRIPTOR;
  Descriptor->Header.Length      = sizeof (EFI_ACPI_GENERIC_REGISTER_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);
  Descriptor->AddressSpaceId    = AddressSpaceKeyword;
  Descriptor->RegisterBitWidth  = RegisterBitWidth;
  Descriptor->RegisterBitOffset = RegisterBitOffset;
  Descriptor->AddressSize       = AccessSize;
  Descriptor->RegisterAddress   = RegisterAddress;
  Object->Completed             = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/*
  19.6.111 QWordSpace (QWord Space Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  QWordSpace (ResourceType, ResourceUsage, Decode, IsMinFixed, IsMaxFixed,
              TypeSpecificFlags, AddressGranularity, AddressMinimum,
              AddressMaximum, AddressTranslation, RangeLength,
              ResourceSourceIndex, ResourceSource, DescriptorName)

  Generates:
  6.4.3.5.1 QWord Address Space Descriptor
  Type 1, Large Item Value 0xA
  The QWORD address space descriptor is used to report resource usage in a
  64-bit address space (like memory and I/O).


  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed QWordSpace buffer

  @retval         EFI_SUCCESS
  @retval         Error status
*/
EFI_STATUS
EFIAPI
AmlOPQWordSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT64  AddressGranularity,
  IN      UINT64  AddressMinimum,
  IN      UINT64  AddressMaximum,
  IN      UINT64  AddressTranslation,
  IN      UINT64  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  // UINT8 ResourceType cannot be > 0xFF, so no need to check top end.
  if (ResourceType < EFI_ACPI_SPACE_RESOURCE_TYPE_MIN) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid ResourceType\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPQWordAddressSpace (
             ResourceType,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             TypeSpecificFlags,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.82 Memory32Fixed (Memory Resource Descriptor Macro)

  Syntax:
    Memory32Fixed (ReadAndWrite, AddressBase, RangeLength, DescriptorName)

  Arguments:
    ReadAndWrite: Specifies whether or not the memory region is read-only (ReadOnly)
    or read/write (ReadWrite). If nothing is specified, then ReadWrite is assumed.
    The 1-bit field DescriptorName._RW is automatically created to refer to this
    portion of the resource descriptor, where '1' is ReadWrite and '0' is ReadOnly.

    AddressBase: Evaluates to a 32-bit integer that specifies the base address
    of the memory range. The 32-bit field DescriptorName. _BAS is automatically
    created to refer to this portion of the resource descriptor.

    RangeLength: Evaluates to a 32-bit integer that specifies the total number of
    bytes decoded in the memory range. The 32-bit field DescriptorName. _LEN is
    automatically created to refer to this portion of the resource descriptor.

    DescriptorName: Is an optional argument that specifies a name for an integer
    constant that will be created in the current scope that contains the offset
    of this resource descriptor within the current resource template buffer. The
    predefined descriptor field names may be appended to this name to access
    individual fields within the descriptor via the Buffer Field operators.

  Description:
    The Memory32Fixed macro evaluates to a buffer which contains a 32-bit memory
    descriptor, which describes a fixed range of memory addresses. The format of
    the fixed 32-bit memory descriptor can be found in 32-Bit Fixed Memory Range
    Descriptor. The macro is designed to be used inside of a ResourceTemplate.

  Generates:
    6.4.3.4 32-Bit Fixed Memory Range Descriptor
    Type 1, Large Item Value 0x6
    This memory range descriptor describes a device's memory resources within a
    32-bit address space.

  @param[in]      ReadAndWrite,
  @param[in]      AddressBase,
  @param[in]      RangeLength,
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed memory resource descriptor

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPMemory32Fixed (
  IN      READ_WRITE_FLAG  ReadAndWrite,
  IN      UINT32           AddressBase,
  IN      UINT32           RangeLength,
  IN OUT  LIST_ENTRY       *ListHead
  )
{
  EFI_STATUS                                     Status;
  AML_OBJECT_INSTANCE                            *Object;
  EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR  *Descriptor;

  if ((ReadAndWrite & (UINT8) ~EFI_ACPI_MEMORY_WRITE_STATUS_MASK) != 0) {
    // Invalid ReadAndWrite value
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ReadAndWrite '%x' is not valid.\n", __FUNCTION__, ReadAndWrite));
    return EFI_INVALID_PARAMETER;
  }

  if (ListHead == NULL) {
    // Invalid
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid parameter, ListHead cannot == NULL.\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a cannot create %a object.", __FUNCTION__, "MEMORY_32_FIXED_RESOURCE"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "MEMORY_32_FIXED_RESOURCE"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor                     = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Header.Byte = ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR;
  Descriptor->Header.Length      = sizeof (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);
  Descriptor->Information = ReadAndWrite;
  Descriptor->BaseAddress = AddressBase;
  Descriptor->Length      = RangeLength;
  Object->Completed       = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.109 QWordIO (QWord IO Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  QWordIO (ResourceUsage, IsMinFixed, IsMaxFixed, Decode, ISARanges,
           AddressGranularity, AddressMinimum, AddressMaximum,
           AddressTranslation, RangeLength, ResourceSourceIndex,
           ResourceSource, DescriptorName, TranslationType,
           TranslationDensity)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Decode,
  @param[in]      ISARanges,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
                  TranslationType - NOT IMPLEMENTED
                  TranslationDensity - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed QWordIO buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPQWordIO (
  IN      UINT8   ResourceUsage,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Decode,
  IN      UINT8   ISARanges,
  IN      UINT64  AddressGranularity,
  IN      UINT64  AddressMinimum,
  IN      UINT64  AddressMaximum,
  IN      UINT64  AddressTranslation,
  IN      UINT64  RangeLength,
  //                    ResourceSourceIndex - NOT IMPLEMENTED
  //                    ResourceSource - NOT IMPLEMENTED
  //                    DescriptorName - NOT IMPLEMENTED
  //                    TranslationType - NOT IMPLEMENTED
  //                    TranslationDensity - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  if (ISARanges == 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges = 0 = Reserved\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  } else if (ISARanges > 3) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges > 3 is Invalid\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPQWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_IO,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             (ISARanges),
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.110 QWordMemory (QWord Memory Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  QWordMemory (ResourceUsage, Decode, IsMinFixed, IsMaxFixed, Cacheable,
               ReadAndWrite, AddressGranularity, AddressMinimum, AddressMaximum,
               AddressTranslation, RangeLength, ResourceSourceIndex,
               ResourceSource, DescriptorName, MemoryRangeType, TranslationType)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Cacheable,
  @param[in]      ReadAndWrite,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
                  MemoryRangeType - NOT IMPLEMENTED
                  TranslationType - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed QWordMemory buffer

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPQWordMemory (
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Cacheable,
  IN      UINT8   ReadAndWrite,
  IN      UINT64  AddressGranularity,
  IN      UINT64  AddressMinimum,
  IN      UINT64  AddressMaximum,
  IN      UINT64  AddressTranslation,
  IN      UINT64  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  //                  MemoryRangeType - NOT IMPLEMENTED
  //                  TranslationType - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  // Validate Type Specific Parameters
  if ((Cacheable & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_MEM) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid Cacheable Parameter 0x%X\n", __FUNCTION__, (Cacheable & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_MEM)));
    return EFI_INVALID_PARAMETER;
  }

  if ((ReadAndWrite & ~EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_MASK_RW) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid ReadAndWrite Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPQWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_MEM,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             (Cacheable | ReadAndWrite),
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/*
  Internal function to create DWord Address Space Descriptors

  This function only requires a single call and therefore no Phases
  Generates:
  6.4.3.5.3 Word Address Space Descriptor
  Type 1, Large Item Value 0x8
  The WORD address space descriptor is used to report resource usage in a
  16-bit address space (like memory and I/O, Bus Number).

  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed WordSpace Descriptor

  @retval         EFI_SUCCESS
  @retval         Error status
*/
EFI_STATUS
EFIAPI
InternalAmlOPWordAddressSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT16  AddressGranularity,
  IN      UINT16  AddressMinimum,
  IN      UINT16  AddressMaximum,
  IN      UINT16  AddressTranslation,
  IN      UINT16  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS                              Status;
  AML_OBJECT_INSTANCE                     *Object;
  EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR  *Descriptor;

  // Vaidate General Flags Input
  if ((ResourceUsage & ~EFI_ACPI_GENERAL_FLAG_MASK_USAGE) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Word Invalid ResourceUsage Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((Decode & ~EFI_ACPI_GENERAL_FLAG_MASK_DEC) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Word Invalid Decode Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMinFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MIF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Word Invalid IsMinFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  if ((IsMaxFixed & ~EFI_ACPI_GENERAL_FLAG_MASK_MAF) != 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Word Invalid IsMaxFixed Parameter\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlAddressSpaceCheck (
             IsMinFixed,
             IsMaxFixed,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             RangeLength
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Word Address Space Check FAILED\n", __FUNCTION__));
    return Status;
  }

  Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
  if (EFI_ERROR (Status)) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __FUNCTION__, "WORD_ADDRESS"));
    goto Done;
  }

  Object->DataSize = sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR);
  Object->Data     = AllocateZeroPool (Object->DataSize);
  if (Object->Data == NULL) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: %a Alloc Failed\n", __FUNCTION__, "DWORD_ADDRESS"));
    Status = EFI_OUT_OF_RESOURCES;
    goto Done;
  }

  Descriptor                     = (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR *)Object->Data;
  Descriptor->Header.Header.Byte = ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR;
  Descriptor->Header.Length      = sizeof (EFI_ACPI_WORD_ADDRESS_SPACE_DESCRIPTOR) -
                                   sizeof (ACPI_LARGE_RESOURCE_HEADER);
  Descriptor->ResType               = ResourceType;
  Descriptor->GenFlag               = IsMinFixed | IsMaxFixed | Decode;
  Descriptor->SpecificFlag          = TypeSpecificFlags;
  Descriptor->AddrSpaceGranularity  = AddressGranularity;
  Descriptor->AddrRangeMin          = AddressMinimum;
  Descriptor->AddrRangeMax          = AddressMaximum;
  Descriptor->AddrTranslationOffset = AddressTranslation;
  Descriptor->AddrLen               = RangeLength;
  Object->Completed                 = TRUE;

Done:
  if (EFI_ERROR (Status)) {
    InternalFreeAmlObject (&Object, ListHead);
  }

  return Status;
}

/**
  19.6.152 WordSpace (Word Space Resource Descriptor Macro) )

  This function only requires a single call and therefore no Phases
  Syntax
  WordSpace (ResourceType, ResourceUsage, Decode, IsMinFixed, IsMaxFixed,
             TypeSpecificFlags, AddressGranularity, AddressMinimum,
             AddressMaximum, AddressTranslation, RangeLength,
             ResourceSourceIndex, ResourceSource, DescriptorName)

  Generates:
  6.4.3.5.3 Word Address Space Descriptor
  Type 1, Large Item Value 0x8

  @param[in]      ResourceType
  @param[in]      ResourceUsage,
  @param[in]      Decode,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      TypeSpecificFlags,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed WordSpace Descriptor

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPWordSpace (
  IN      UINT8   ResourceType,
  IN      UINT8   ResourceUsage,
  IN      UINT8   Decode,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   TypeSpecificFlags,
  IN      UINT16  AddressGranularity,
  IN      UINT16  AddressMinimum,
  IN      UINT16  AddressMaximum,
  IN      UINT16  AddressTranslation,
  IN      UINT16  RangeLength,
  //                  ResourceSourceIndex - NOT IMPLEMENTED
  //                  ResourceSource - NOT IMPLEMENTED
  //                  DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  // UINT8 ResourceType cannot be > 0xFF, so no need to check top end.
  if (ResourceType < EFI_ACPI_SPACE_RESOURCE_TYPE_MIN) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid ResourceType\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPWordAddressSpace (
             ResourceType,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             TypeSpecificFlags,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.150 WordBusNumber (Word Bus Number Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  WordBusNumber (ResourceUsage, IsMinFixed, IsMaxFixed, Decode,
                 AddressGranularity, AddressMinimum, AddressMaximum,
                 AddressTranslation, RangeLength, ResourceSourceIndex,
                 ResourceSource, DescriptorName)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Decode,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed WordBusNumber
                              Descriptor

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPWordBusNumber (
  IN      UINT8   ResourceUsage,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Decode,
  IN      UINT16  AddressGranularity,
  IN      UINT16  AddressMinimum,
  IN      UINT16  AddressMaximum,
  IN      UINT16  AddressTranslation,
  IN      UINT16  RangeLength,
  //                    ResourceSourceIndex - NOT IMPLEMENTED
  //                    ResourceSource - NOT IMPLEMENTED
  //                    DescriptorName - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  Status = InternalAmlOPWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_BUS,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             0,
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}

/**
  19.6.151 WordIO (Word IO Resource Descriptor Macro)

  This function only requires a single call and therefore no Phases
  Syntax
  WordIO (ResourceUsage, IsMinFixed, IsMaxFixed, Decode, ISARanges,
          AddressGranularity, AddressMinimum, AddressMaximum,
          AddressTranslation, RangeLength, ResourceSourceIndex,
          ResourceSource, DescriptorName, TranslationType, TranslationDensity)

  defines for pass in parameters can be found in:
  MdePkg/Include/IndustryStandard/Acpi10.h

  @param[in]      ResourceUsage,
  @param[in]      IsMinFixed,
  @param[in]      IsMaxFixed,
  @param[in]      Decode,
  @param[in]      ISARanges,
  @param[in]      AddressGranularity,
  @param[in]      AddressMinimum,
  @param[in]      AddressMaximum,
  @param[in]      AddressTranslation,
  @param[in]      RangeLength,
                  ResourceSourceIndex - NOT IMPLEMENTED
                  ResourceSource - NOT IMPLEMENTED
                  DescriptorName - NOT IMPLEMENTED
                  TranslationType - NOT IMPLEMENTED
                  TranslationDensity - NOT IMPLEMENTED
  @param[in,out]  ListHead  - Linked list has completed WordIO Descriptor

  @retval         EFI_SUCCESS
  @retval         Error status
**/
EFI_STATUS
EFIAPI
AmlOPWordIO (
  IN      UINT8   ResourceUsage,
  IN      UINT8   IsMinFixed,
  IN      UINT8   IsMaxFixed,
  IN      UINT8   Decode,
  IN      UINT8   ISARanges,
  IN      UINT16  AddressGranularity,
  IN      UINT16  AddressMinimum,
  IN      UINT16  AddressMaximum,
  IN      UINT16  AddressTranslation,
  IN      UINT16  RangeLength,
  //                    ResourceSourceIndex - NOT IMPLEMENTED
  //                    ResourceSource - NOT IMPLEMENTED
  //                    DescriptorName - NOT IMPLEMENTED
  //                    TranslationType - NOT IMPLEMENTED
  //                    TranslationDensity - NOT IMPLEMENTED
  IN OUT  LIST_ENTRY  *ListHead
  )
{
  EFI_STATUS  Status;

  if (ISARanges == 0) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges = 0 = Reserved\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  } else if (ISARanges > 3) {
    DEBUG ((DEBUG_ERROR, "%a: ERROR: ISARanges > 3 is Invalid\n", __FUNCTION__));
    return EFI_INVALID_PARAMETER;
  }

  Status = InternalAmlOPWordAddressSpace (
             ACPI_ADDRESS_SPACE_TYPE_IO,
             ResourceUsage,
             Decode,
             IsMinFixed,
             IsMaxFixed,
             (ISARanges),
             AddressGranularity,
             AddressMinimum,
             AddressMaximum,
             AddressTranslation,
             RangeLength,
             ListHead
             );
  return Status;
}
